#ifndef __GPU_DEVICE_FUNCTIONS_CU__
#define __GPU_DEVICE_FUNCTIONS_CU__

#include "Neural_Network_Config.h"
#include "Genetic_Algorithm_Config.h"


__device__ void feedForward(Chrosomome chr, float* data, float *result){
	
	
		float neurons[NEURON_NUM];
		int chromosomeIndex = 0;
	
	
		//load input
		for (int i = 0 ; i < INPUT_NUM ; i++)
		{
			neurons[i] = data[i];
		}
	
		for(int i = 1 ; i < LAYER_NUM ; i++){ //for each layer
	
			//find total neurons in previous layers
			int preNeuronsNum = 0;
			for(int t = 0 ; t < i ; t++){
				preNeuronsNum += layerNums[t];
			}
	
			/*int j		= preNeuronsNum;
			int index	= 0;*/
	
			for(int j = preNeuronsNum, int index = 0 ; j < layerNums[i] + preNeuronsNum , index < layerNums[i] ; j++, index++){
	
				float sum = 0;
				for(int k = layerNums[i-1] -1 ; k >=0 ; k--){
	
					sum += neurons[j - index - (k + 1)] * chr [chromosomeIndex++];
				}
				//add bias
				sum += chr[chromosomeIndex++];
	
				//sigmoid
				float calc = expf(-1 * sum);
				calc += 1.0f;
				calc = 1.0f / calc;
	
				//store value
				neurons[j] = calc;
				
			/*	j++;
				index++;*/
	
			}
	
			
		}
	
		//load output
		int resIndex = 0;
		for(int i = NEURON_NUM - OUTPUT_NUM ; i < NEURON_NUM ; i++){
		
			result[resIndex] = neurons[i];
			resIndex++;
		}
	
		
	}

__device__ float getANNerror(float* actual, float *desired){
	float error = 0.0f;
	for(int i = 0 ; i < OUTPUT_NUM ; i++){
		error += (*(desired + i) - *(actual + i)) * (*(desired + i) - *(actual + i));
	}
	return error/2; 	
}

__device__ void mutate(float *r1, float *r2, float *r3,float *mutVec){
	

	for(int i = 0 ; i < CONNECTION_NUM ; i++){
		mutVec[i] = r1[i] + MUTATION_RATE * (r3[i]  - r2[i]);
	}

}

__device__ void crossover(float *original, float *trivial, float *randomNumbers, float *crossed){

	
	float rn;

	for(int i = 0 ; i < CONNECTION_NUM ; i++){
		rn = randomNumbers[i];
		if(rn <= CROSSOVER_RATE){
			crossed[i]  = trivial[i];
		}else{
			crossed[i] = original[i];
		}
	}


}

__device__ void findMinFitness(float* fitnessVec, float *result){

	*result = fitnessVec[0];
	for(int i = 1 ; i < MAX_POPULATION ; i++){
		if(fitnessVec[i] < *result){
			*result = fitnessVec[i];
		}
	}
}
//__device__ float sigmoid(const float input)
//{
//	float calc = expf(-1 * input);
//	calc += 1;
//	calc = 1 / calc;
//	return calc;
//}
#endif